package org.jsola.hr.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jsola.common.DateKit;
import org.jsola.common.StrKit;
import org.jsola.core.Page;
import org.jsola.exception.ParamException;
import org.jsola.hr.constant.CompanySysNoticeStatus;
import org.jsola.hr.constant.ConfigCodeConstants;
import org.jsola.hr.constant.EmpInfoStatus;
import org.jsola.hr.constant.HrConstants;
import org.jsola.hr.dao.IEmpNoticeDAO;
import org.jsola.hr.dto.EmpNoticeAddDTO;
import org.jsola.hr.dto.EmpNoticeUpdateDTO;
import org.jsola.hr.dto.TaskAddDTO;
import org.jsola.hr.entity.EmpInfoDO;
import org.jsola.hr.entity.EmpNoticeDO;
import org.jsola.hr.entity.TaskDO;
import org.jsola.hr.provider.IMessageProviderService;
import org.jsola.hr.provider.ISiteConfigProviderService;
import org.jsola.hr.provider.IUserProviderService;
import org.jsola.hr.query.EmpNoticeQuery;
import org.jsola.hr.service.IEmpInfoService;
import org.jsola.hr.service.IEmpNoticeService;
import org.jsola.hr.service.IEmpNoticeTaskService;
import org.jsola.hr.service.ITaskService;
import org.jsola.hr.vo.EmpInfoListVO;
import org.jsola.hr.vo.EmpNoticeListVO;
import org.jsola.hr.vo.EmpNoticeVO;
import org.jsola.hr.vo.TaskVO;
import org.jsola.message.dto.*;
import org.jsola.user.core.TokenUser;
import org.jsola.user.entity.UnionOpenIdDO;
import org.jsola.user.entity.UserDO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.util.HtmlUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.*;
import java.util.stream.Collectors;


/**
 * 员工通知
 *
 * @author zhr
 */
@Slf4j
@Service("hrEmpNoticeServiceImpl")
public class EmpNoticeServiceImpl implements IEmpNoticeService {

    @Autowired
    private IEmpNoticeDAO empNoticeDAO;

    @Autowired
    private IEmpInfoService empInfoService;

    @Autowired
    private IUserProviderService userProviderService;

    @Autowired
    private IMessageProviderService messageProviderService;

    @Autowired
    private ITaskService taskService;

    @Autowired
    private ThreadPoolTaskScheduler threadPoolTask;

    @Autowired
    private IEmpNoticeTaskService empNoticeTaskService;

    @Autowired
    private ISiteConfigProviderService siteConfigProviderService;

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public EmpNoticeVO save(EmpNoticeAddDTO empNoticeAddDTO, TokenUser tokenUser) {
        // 转DO
        EmpNoticeDO empNoticeDO = empNoticeAddDTO.to(EmpNoticeDO.class);
        empNoticeDO.setStatus(HrConstants.READ_STATUS_NO);

        ParamException.hasText(empNoticeDO.getNoticeType(), "请选择通知方式");

        // 立即发布
        if (empNoticeAddDTO.getIsPublishNow()) {
            empNoticeDO.setPublishDate(new Date());
        } else {
            ParamException.notNull(empNoticeDO.getPublishDate(), "非立即发布请选择发布时间");
            if (empNoticeDO.getPublishDate().before(new Date())) {
                throw new ParamException("定时发布请不要选择过去的时间点");
            }
        }

        // 根据选择的员工和员工类型,获取最终的发布人员
        getFinalEmpRange(empNoticeDO, empNoticeAddDTO.getPublishEmpIds(), tokenUser);

        // 发布时间早于当前时间
        empNoticeDO.setStatus(CompanySysNoticeStatus.WAIT.getValue());
        if (Objects.nonNull(empNoticeDO.getPublishDate()) && empNoticeDO.getPublishDate().before(new Date())) {
            empNoticeDO.setStatus(CompanySysNoticeStatus.HAS.getValue());
        }

        empNoticeDO.setReadStatus(HrConstants.READ_STATUS_NO);
        empNoticeDO.setCreateUserName(tokenUser.getUserName());
        // 处理富文本
        handleRichText(empNoticeDO);
        empNoticeDO.setIsOnline(true);
        // 创建人名称
        empNoticeDO.setCreateUserName(tokenUser.getUserName());

        // 保存
        empNoticeDO = save(empNoticeDO, tokenUser.getSiteId(), tokenUser.getUserId());

        // 非立即发布,增加定时任务
        if (!empNoticeAddDTO.getIsPublishNow()) {
            addTask(empNoticeDO, true, tokenUser);
        }
        // 微信公众号推送模板消息
        if (empNoticeAddDTO.getIsPublishNow()) {
            List<String> noticeTypeList = Arrays.asList(empNoticeAddDTO.getNoticeType().split(","));
            if (noticeTypeList.contains(HrConstants.NOTICE_TYPE_WECHAT)) {
                // 发送微信模板消息推送
                sendWeiXinTemp(empNoticeDO, tokenUser);
            } else if (noticeTypeList.contains(HrConstants.NOTICE_TYPE_TEXT)) {
                // 发短信
                sendTextTemp(empNoticeDO, tokenUser);
            } else if (noticeTypeList.contains(HrConstants.NOTICE_TYPE_EMAIL)) {
                // 发邮件
                sendEmailTemp(empNoticeDO, tokenUser);
            }
        }

        return empNoticeDO.to(EmpNoticeVO.class);
    }

    /**
     * @param empNoticeDO   员工信息
     * @param publishEmpIds 发布员工
     * @param tokenUser     当前用户
     */
    private void getFinalEmpRange(EmpNoticeDO empNoticeDO, String[] publishEmpIds, TokenUser tokenUser) {

        List<EmpInfoDO> empInfoDOList = new ArrayList<>();
        // 全公司
        if (empNoticeDO.getPublishEmpRangeIsAll()) {
            // 正式类型
            Integer formalType = empNoticeDO.getFormalType();
            List<String> formalTypeList = Collections.singletonList(formalType + "");
            // 公司id
            String companyId = empNoticeDO.getCompanyId();
            empInfoDOList = empInfoService.selectOnJobEmpListByFormalTypeAndCompanyIdAndPostType(formalTypeList,
                    companyId, null, tokenUser);
        }
        // 部分员工
        else {
            if (publishEmpIds != null && publishEmpIds.length > 0) {
                empInfoDOList = empInfoService.selectDoByIds(Arrays.asList(publishEmpIds));
            }
        }

        // 符合条件的员工
        ParamException.notEmpty(empInfoDOList, "没有需要发送的员工");
        List<String> finalEmpIdList = empInfoDOList.stream()
                .map(EmpInfoDO::getId)
                .filter(StringUtils::isNotEmpty)
                .collect(Collectors.toList());

        List<String> userIdList = empInfoDOList.stream()
                .map(EmpInfoDO::getUserId)
                .filter(StringUtils::isNotEmpty)
                .collect(Collectors.toList());
        ParamException.notEmpty(userIdList, "没有要发送的用户");
        empNoticeDO.setPublishEmpId(String.join(",", finalEmpIdList));
        empNoticeDO.setPublishUserId(String.join(",", userIdList));
        empNoticeDO.setNoReadEmpIds(empNoticeDO.getPublishEmpId());
        empNoticeDO.setNoReadCount(finalEmpIdList.size());
        empNoticeDO.setReadCount(0);
    }

    /**
     * 添加定时任务
     *
     * @param empNoticeDO 任务信息
     * @param isOnline    上线还是下线
     * @param tokenUser   当前用户
     */
    private void addTask(EmpNoticeDO empNoticeDO, boolean isOnline, TokenUser tokenUser) {
        // 添加记录,重试系统时加载
        TaskAddDTO taskAddDTO = new TaskAddDTO();
        taskAddDTO.setSubjectType(HrConstants.NOTICE_SUBJECT_TYPE_EMP);
        taskAddDTO.setSubjectId(empNoticeDO.getId());
        taskAddDTO.setDescription("个人通知定时任务");
        taskAddDTO.setRunBeanName("hrEmpNoticeServiceImpl");

        Date runDate;
        if (isOnline) {
            // 上线
            taskAddDTO.setRunType(HrConstants.SYS_NOTICE_ONLINE);
            runDate = empNoticeDO.getPublishDate();
        } else {
            // 下线
            taskAddDTO.setRunType(HrConstants.SYS_NOTICE_OFFLINE);
            runDate = empNoticeDO.getOfflineDate();
        }
        // 运行时间早于当前时间,用当前时间的下一分钟
        if (runDate == null || runDate.before(new Date())) {
            runDate = DateKit.getBeforeMinute(new Date(), 1);
        }
        taskAddDTO.setRunDate(runDate);
        taskAddDTO.setStatus(false);
        TaskVO taskVO = taskService.save(taskAddDTO, tokenUser);

        // 添加运行定时任务
        Runnable runnable = new EmpNoticeTask(taskVO.getId());
        threadPoolTask.schedule(runnable, runDate);
    }

    public class EmpNoticeTask implements Runnable {
        private String taskId;

        EmpNoticeTask(String taskId) {
            this.taskId = taskId;
        }

        @Override
        public void run() {
            TaskDO task = taskService.selectDOById(taskId, "");
            if (Objects.nonNull(task)) {
                empNoticeTaskService.runTask(taskId);
            }
        }
    }

    /**
     * 发送微信通知
     *
     * @param empNoticeDO 个人通知
     * @param tokenUser   当前用户
     */
    private void sendWeiXinTemp(EmpNoticeDO empNoticeDO, TokenUser tokenUser) {
        String[] empIds = empNoticeDO.getPublishEmpId().split(",");
        if (empIds.length > 0) {
            String id = empNoticeDO.getId();
            List<EmpInfoDO> empInfoList = empInfoService.listByIds(tokenUser.getSiteId(), empIds);
            if (!CollectionUtils.isEmpty(empInfoList)) {
                // 用户openId集合
                for (EmpInfoDO empInfo : empInfoList) {
                    // 公众号appid配置
                    String appid = siteConfigProviderService.selectValueByCode(ConfigCodeConstants.CODE_APPID,
                            tokenUser.getSiteId());
                    // 用户openId集合
                    UnionOpenIdDO unionOpenIdDO = userProviderService.getUnionOpenByUserId(appid, empInfo.getUserId());
                    if (Objects.nonNull(unionOpenIdDO) && StringUtils.isNotBlank(unionOpenIdDO.getOpenId())) {
                        String templateId = siteConfigProviderService.selectValueByCode(ConfigCodeConstants.CODE_COMPANY_EMP_NOTICE_TEMPLATE_ID, tokenUser.getSiteId());
                        /**
                         * {{first.DATA}}
                         * 信息类别：{{keyword1.DATA}}
                         * 信息名称：{{keyword2.DATA}}
                         * 信息简介：{{keyword3.DATA}}
                         * {{remark.DATA}}
                         */
                        // 推送微信模板消息
                        WeiXinDTO weiXinDTO = new WeiXinDTO();
                        weiXinDTO.setAppId(appid);
                        weiXinDTO.setTemplateId(templateId);
                        weiXinDTO.setToUser(unionOpenIdDO.getOpenId());
                        // 参数
                        List<WxTemplateParam> paramList = new ArrayList<>();
                        WxTemplateParam param1 = new WxTemplateParam();
                        param1.setName("first");
                        param1.setValue("您有一条新的个人通知，请及时查看");
                        paramList.add(param1);
                        WxTemplateParam param2 = new WxTemplateParam();
                        param2.setName("keyword1");
                        param2.setValue("个人通知");
                        paramList.add(param2);
                        WxTemplateParam param3 = new WxTemplateParam();
                        param3.setName("keyword2");
                        param3.setValue(empNoticeDO.getTitle());
                        paramList.add(param3);
                        WxTemplateParam param4 = new WxTemplateParam();
                        param4.setName("keyword3");
                        if (empNoticeDO.getContent().length() > 60) {
                            param4.setValue(empNoticeDO.getContent().substring(0, 59) + "...");
                        } else {
                            param4.setValue(empNoticeDO.getContent());
                        }
                        paramList.add(param4);
                        WxTemplateParam param5 = new WxTemplateParam();
                        param5.setName("remark");
                        param5.setValue("点击查看详情");
                        paramList.add(param5);

                        weiXinDTO.setTemplateParamList(paramList);
                        // 跳转小程序
                        WxMiNiParam wxMiNiParam = new WxMiNiParam();
                        // 小程序appid配置
                        String miniAppid = siteConfigProviderService.selectValueByCode(ConfigCodeConstants.CODE_MINI_APPID,
                                tokenUser.getSiteId());
                        // 小程序首页配置
                        String pagePath = siteConfigProviderService.selectValueByCode(ConfigCodeConstants.CODE_PATH_EMPNOTICE,
                                tokenUser.getSiteId());
                        wxMiNiParam.setAppid(miniAppid);
                        wxMiNiParam.setPagepath(pagePath + "?id=" + id);
                        weiXinDTO.setMiniProgram(wxMiNiParam);
                        messageProviderService.sendWeChatTempMessage(weiXinDTO, tokenUser);
                    }
                }
            }
        }
    }

    /**
     * 发送短信通知
     *
     * @param empNoticeDO 个人通知
     * @param tokenUser   当前用户
     */
    private void sendTextTemp(EmpNoticeDO empNoticeDO, TokenUser tokenUser) {
        /*// 短信通知
        List<String> empIdList = Arrays.asList(empNoticeDO.getPublishEmpId().split(","));
        List<EmpInfoDO> empInfoDOList = empInfoService.selectDoByIds(empIdList);
        int size = empInfoDOList.size();
        ShortMessageDTO shortMessageDTO = new ShortMessageDTO();
        shortMessageDTO.setScene("企业公告");
        String thirdId = siteConfigProviderService.selectValueByCode(ConfigCodeConstants.CODE_SMS_TEMPLATE_ID, tokenUser.getSiteId());
        shortMessageDTO.setThirdId(thirdId);
        // 写入短信内容
        long startTime = System.currentTimeMillis();
        // 阿里云批量发送上限为1000
        int sentMessagesMaxNumber = 1000;
        if (size <= sentMessagesMaxNumber) {
            String phoneNumbers = empInfoDOList.parallelStream()
                    .map(EmpInfoDO::getPhone)
                    .distinct()
                    .collect(Collectors.joining(","));
            // TODO 替换测试手机号
             shortMessageDTO.setPhone(phoneNumbers);
            messageProviderService.sendShortMessage(shortMessageDTO, tokenUser);
            long endTime = System.currentTimeMillis();
            log.debug("批量发送企业公告{}条短信,耗时{}ms", size, endTime - startTime);
        } else {
            int count = (size + sentMessagesMaxNumber - 1) / sentMessagesMaxNumber;
            List<String> phoneList = new ArrayList<>();
            for (int i = 0; i < count; i++) {
                List<String> phoneNumberList;
                if (i == 0) {
                    phoneNumberList = phoneList.subList(i, sentMessagesMaxNumber);
                } else if (i == count - 1) {
                    phoneNumberList = phoneList.subList(i * sentMessagesMaxNumber, size);
                } else {
                    phoneNumberList = phoneList.subList(i * sentMessagesMaxNumber, (i + 1) * sentMessagesMaxNumber);
                }
                String phoneNumbers = phoneNumberList.parallelStream().collect(Collectors.joining(","));
                 shortMessageDTO.setPhone(phoneNumbers);
                messageProviderService.sendShortMessage(shortMessageDTO, tokenUser);
                long endTime = System.currentTimeMillis();
                log.debug("批量发送企业公告{}条短信,耗时{}ms", phoneNumberList.size(), endTime - startTime);
            }
        }*/
    }

    /**
     * 发送邮件通知
     *
     * @param empNoticeDO 个人通知
     * @param tokenUser   当前用户
     */
    private void sendEmailTemp(EmpNoticeDO empNoticeDO, TokenUser tokenUser) {
        /*// 邮件通知
        List<String> empIdList = Arrays.asList(empNoticeDO.getPublishEmpId().split(","));
        String email = siteConfigProviderService.selectValueByCode(ConfigCodeConstants.CODE_SENDER_EMAIL, tokenUser.getSiteId());
        List<EmpInfoDO> empInfoDOList = empInfoService.selectDoByIds(empIdList);
        List<String> emailList = empInfoDOList.parallelStream()
                .map(EmpInfoDO::getEmail)
                .filter(StringUtils::isNotBlank)
                .collect(Collectors.toList());
        EmailDTO emailDTO = new EmailDTO();
        emailDTO.setTemplateId(0L);
        emailDTO.setSenderEmail(email);
        emailDTO.setSubjectNoTemp("企业公告");
        emailDTO.setContentNoTemp(empNoticeDO.getContent());
         emailDTO.setToEmailList(emailList);
        messageProviderService.sendEmail(emailDTO, tokenUser);*/
    }


    /**
     * 反转译标题/内容富文本
     *
     * @param empNoticeDO 信息
     */
    private void handleRichText(EmpNoticeDO empNoticeDO) {
        // 富文本反转义
        if (StringUtils.isNotEmpty(empNoticeDO.getTitle())) {
            String title = HtmlUtils.htmlUnescape(empNoticeDO.getTitle());
            title = title.replaceAll("&nbsp;", " ");
            empNoticeDO.setTitle(title);
        }
        if (StringUtils.isNotEmpty(empNoticeDO.getContent())) {
            String content = HtmlUtils.htmlUnescape(empNoticeDO.getContent());
            content = content.replaceAll("&nbsp;", " ");
            empNoticeDO.setContent(content);
        }
        if (StringUtils.isNotEmpty(empNoticeDO.getContentHasStyle())) {
            String contentHasStyle = HtmlUtils.htmlUnescape(empNoticeDO.getContentHasStyle());
            contentHasStyle = contentHasStyle.replaceAll("&nbsp;", " ");
            empNoticeDO.setContentHasStyle(contentHasStyle);
        }
    }


    /**
     * 获取需要发送的人员
     *
     * @param empIdList     员工
     * @param publishEmpIds 员工
     * @param tokenUser     当前用户
     * @return 需要发送的员工
     */
    private EmpInfoDO getEmpInfoListByChoose(List<String> empIdList, String publishEmpIds, TokenUser tokenUser) {
        if (CollectionUtils.isEmpty(empIdList)) {
            empIdList = new ArrayList<>();
        }
        if (StringUtils.isNotEmpty(publishEmpIds)) {
            empIdList.addAll(Arrays.asList(publishEmpIds.split(",")));
        }
        if (CollectionUtils.isEmpty(empIdList)) {
            return null;
        }
        if (empIdList.size() > 1) {
            throw new ParamException("个人通知暂不支持多人发送");
        }
        String empId = empIdList.get(0);
        EmpInfoDO empInfoDO = empInfoService.selectDOById(empId, tokenUser.getSiteId());
        if (Objects.nonNull(empInfoDO)) {
            if (empInfoDO.getStatus().equals(EmpInfoStatus.HAS_ENTRY.getValue())
                    || empInfoDO.getStatus().equals(EmpInfoStatus.WAIT_QUIT.getValue())) {
                // 在职员工或待离职员工
                return empInfoDO;
            }
        }
        return null;
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int update(EmpNoticeUpdateDTO empNoticeUpdateDTO, TokenUser tokenUser) {
        //转DO
        EmpNoticeDO empNoticeDO = empNoticeUpdateDTO.to(EmpNoticeDO.class);
        ParamException.hasText(empNoticeDO.getNoticeType(), "请选择通知方式");

        // 获取要发送的人员
        // 根据选择的员工和员工类型,获取最终的发布人员
        getFinalEmpRange(empNoticeDO, empNoticeUpdateDTO.getEmpIdList(), tokenUser);

        // 处理富文本
        handleRichText(empNoticeDO);

        //根据主键更新，只更新非null值
        return updateByIdSelective(empNoticeDO, tokenUser.getSiteId(), tokenUser.getUserId());
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int deleteByIds(TokenUser tokenUser, String... empNoticeIds) {
        return logicalDeleteByIds(tokenUser.getSiteId(), tokenUser.getUserId(), (Object[]) empNoticeIds);
    }


    @Override
    public EmpNoticeVO selectById(String empNoticeId, TokenUser tokenUser) {
        EmpNoticeDO empNoticeDO = selectDOById(empNoticeId, tokenUser.getSiteId());
        if (empNoticeDO == null) {
            return null;
        }
        EmpNoticeVO empNoticeVO = empNoticeDO.to(EmpNoticeVO.class);
        // 员工id
        String finalEmpIds = empNoticeVO.getPublishEmpId();
        List<EmpInfoDO> empInfoDOList;
        if (StringUtils.isNotBlank(finalEmpIds)) {
            List<String> empIdList = Arrays.asList(finalEmpIds.split(","));
            empInfoDOList = empInfoService.selectDoByIds(empIdList);
        } else {
            // 正式类型
            Integer formalType = empNoticeVO.getFormalType();
            List<String> formalTypeList = Collections.singletonList(formalType + "");
            // 公司id
            String companyId = empNoticeVO.getCompanyId();
            // 是否全公司发布
            Boolean publishEmpRangeIsAll = empNoticeVO.getPublishEmpRangeIsAll();
            if (publishEmpRangeIsAll) {
                empInfoDOList = empInfoService.selectOnJobEmpListByFormalTypeAndCompanyIdAndPostType(formalTypeList,
                        companyId, null, tokenUser);
            } else {
                // 是否全部员工类型发布(1:全部员工类型,0:部分员工类型)
                Boolean publishEmpTypeIsAll = empNoticeVO.getPublishEmpTypeIsAll();
                if (publishEmpTypeIsAll) {
                    empInfoDOList = empInfoService.selectOnJobEmpListByFormalTypeAndCompanyIdAndPostType(formalTypeList,
                            companyId, null, tokenUser);
                } else {
                    // 部分员工类型时选择的员工类型code(用,分隔)
                    String publishEmpType = empNoticeVO.getPublishEmpType();
                    String[] split = publishEmpType.split(",");
                    List<String> publishEmpTypeList = Arrays.asList(split);
                    empInfoDOList = empInfoService.selectOnJobEmpListByFormalTypeAndCompanyIdAndPostType(formalTypeList,
                            companyId, publishEmpTypeList, tokenUser);
                }
            }
        }
        // 已读员工
        String readEmpIds = empNoticeVO.getReadEmpIds();
        List<String> readEmpIdList = new ArrayList<>();
        if (StringUtils.isNotBlank(readEmpIds)) {
            readEmpIdList = Arrays.asList(readEmpIds.split(","));
        }

        // 符合条件的员工
        List<EmpInfoListVO> empInfoListVOS = empInfoDOList.stream()
                .map(empInfoDO -> empInfoDO.to(EmpInfoListVO.class))
                .collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(readEmpIdList)) {
            for (EmpInfoListVO empInfoListVO : empInfoListVOS) {
                empInfoListVO.setIsRead(readEmpIdList.contains(empInfoListVO.getId()));
            }
        }
        empNoticeVO.setEmpInfoList(empInfoListVOS);
        return empNoticeVO;
    }

    @Override
    public List<EmpNoticeListVO> select(EmpNoticeQuery empNoticeQuery, String siteId) {
        ParamException.notNull(empNoticeQuery.getPublishEmpId(), "员工id不能为空");
        Example example = new Example(EmpNoticeDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        if (empNoticeQuery.getCompanyId() != null) {
            example.and().andEqualTo("companyId", empNoticeQuery.getCompanyId());
        }
        if (empNoticeQuery.getPublishEmpId() != null) {
            example.and().andCondition("FIND_IN_SET('" + empNoticeQuery.getPublishEmpId() + "',publish_emp_id)");
        }
        List<EmpNoticeDO> empNoticeDOList = empNoticeDAO.selectByExample(example);
        if (CollectionUtils.isEmpty(empNoticeDOList)) {
            return empNoticeDOList == null ? null : new ArrayList<>();
        }
        // 增加发送的员工姓名
        return addEmpInfoToNoticeList(empNoticeDOList, siteId);
    }

    @Override
    public int selectCount(EmpNoticeQuery empNoticeQuery, String siteId) {
        Example example = buildExample(empNoticeQuery, siteId);
        return empNoticeDAO.selectCountByExample(example);
    }

    @Override
    public Page<EmpNoticeListVO> selectPage(EmpNoticeQuery empNoticeQuery, String siteId) {
        Example example = buildExample(empNoticeQuery, siteId);
        Page<EmpNoticeDO> page = empNoticeDAO.selectPageByExample(example,
                empNoticeQuery.getPageNo(),
                empNoticeQuery.getPageSize());

        Page<EmpNoticeListVO> pageVo = page.to(EmpNoticeListVO.class);
        if (!CollectionUtils.isEmpty(page.getEntities())) {
            List<EmpNoticeDO> empNoticeDOList = page.getEntities();
            List<EmpNoticeListVO> empNoticeVoList = addEmpInfoToNoticeList(empNoticeDOList, siteId);
            pageVo.setEntities(empNoticeVoList);
        }
        return pageVo;
    }

    @Override
    public EmpNoticeDO selectDOById(String empNoticeId, String siteId) {
        return listById(empNoticeId, siteId);
    }

    @Override
    public List<EmpNoticeDO> selectDO(EmpNoticeQuery empNoticeQuery, String siteId) {
        Example example = buildExample(empNoticeQuery, siteId);
        return empNoticeDAO.selectByExample(example);
    }

    @Override
    public List<EmpNoticeListVO> listLastOneUserNotice(EmpNoticeQuery empNoticeQuery, String siteId) {
        List<EmpNoticeDO> empNoticeList = listLastOneUserNoticeDo(empNoticeQuery, siteId);
        if (CollectionUtils.isEmpty(empNoticeList)) {
            return new ArrayList<>();
        }
        // 增加发送的员工姓名
        return addEmpInfoToNoticeList(empNoticeList, siteId);
    }

    /**
     * 增加发送的员工姓名
     *
     * @param empNoticeList 个人通知列表
     * @param siteId        站点id
     */
    private List<EmpNoticeListVO> addEmpInfoToNoticeList(List<EmpNoticeDO> empNoticeList, String siteId) {
        if (CollectionUtils.isEmpty(empNoticeList)) {
            return new ArrayList<>();
        }
        List<EmpNoticeListVO> empNoticeVoList = empNoticeList.stream().map(empNoticeDO -> {
            EmpNoticeListVO empNoticeListVO = empNoticeDO.to(EmpNoticeListVO.class);
            // 已读人员
            if (StringUtils.isNotBlank(empNoticeDO.getReadEmpIds())) {
                empNoticeListVO.setReadEmpInformation(getEmpInformation(empNoticeDO.getReadEmpIds()));
            }
            // 未读人员
            if (StringUtils.isNotBlank(empNoticeDO.getNoReadEmpIds())) {
                empNoticeListVO.setNoReadEmpInformation(getEmpInformation(empNoticeDO.getNoReadEmpIds()));
            }
            return empNoticeListVO;
        }).collect(Collectors.toList());
        String[] empIds = empNoticeList.parallelStream()
                .map(EmpNoticeDO::getPublishEmpId)
                .toArray(String[]::new);

        List<EmpInfoDO> empInfoList = empInfoService.listEmpInfoByIds(siteId, empIds);
        if (CollectionUtils.isEmpty(empInfoList)) {
            return empNoticeVoList;
        }
        // <员工id,员工名称>
        Map<String, String> empInfoMap = empInfoList.parallelStream().collect(
                Collectors.toMap(
                        EmpInfoDO::getId,
                        EmpInfoDO::getName
                )
        );
        empNoticeVoList.parallelStream().forEach(
                empNotice -> {
                    if (empInfoMap.containsKey(empNotice.getPublishEmpId())) {
                        empNotice.setEmpName(empInfoMap.get(empNotice.getPublishEmpId()));
                    }
                }
        );
        return empNoticeVoList;
    }


    /**
     * 员工Id字符串 查找员工姓名及头像
     *
     * @param empIds 员工Id
     * @return 员工姓名及头像
     */
    private List<EmpNoticeListVO.EmpInformation> getEmpInformation(String empIds) {
        if (StringUtils.isBlank(empIds)) {
            return new ArrayList<>();
        }
        String[] split = empIds.split(",");
        List<String> readEmpIds = Arrays.asList(split);
        List<EmpInfoDO> empInfoDOList = empInfoService.selectDoByIds(readEmpIds);
        if (CollectionUtils.isEmpty(empInfoDOList)) {
            return new ArrayList<>();

        }
        List<EmpNoticeListVO.EmpInformation> empInformationList = new ArrayList<>();
        for (EmpInfoDO empInfoDO : empInfoDOList) {
            EmpNoticeListVO.EmpInformation empInformation = new EmpNoticeListVO.EmpInformation();
            empInformation.setEmpName(empInfoDO.getName());
            if (empInfoDO.getUserId() != null) {
                UserDO userDO = userProviderService.selectUserById(empInfoDO.getUserId());
                if (userDO != null) {
                    empInformation.setAvatar(userDO.getAvatar());
                }
            }
            empInformationList.add(empInformation);
        }
        return empInformationList;
    }

    /**
     * 根据条件查询个人通知,只展示最新的一条
     *
     * @param empNoticeQuery 查询条件
     * @param siteId         站点id
     * @return 个人通知最新一条
     */
    private List<EmpNoticeDO> listLastOneUserNoticeDo(EmpNoticeQuery empNoticeQuery, String siteId) {
        empNoticeQuery.setSiteId(siteId);
        return empNoticeDAO.listLastOneUserNotice(empNoticeQuery);
    }

    @Override
    public Page<EmpNoticeListVO> pageLastOneUserNotice(EmpNoticeQuery empNoticeQuery, String siteId) {
        // 分页查询
        PageInfo<EmpNoticeDO> pageDoInfo = PageHelper.startPage(empNoticeQuery.getPageNo(), empNoticeQuery.getPageSize()).doSelectPageInfo(() -> {
            listLastOneUserNoticeDo(empNoticeQuery, siteId);
        });
        List<EmpNoticeDO> empNoticeDoList = pageDoInfo.getList();
        List<EmpNoticeListVO> empNoticeLis = new ArrayList<>();
        if (!CollectionUtils.isEmpty(empNoticeDoList)) {
            // 获取用户已阅信息等
            empNoticeLis = addEmpInfoToNoticeList(empNoticeDoList, siteId);
        }
        return new Page(empNoticeLis, pageDoInfo.getPageNum(), pageDoInfo.getPageSize(), (int) pageDoInfo.getTotal());
    }

    @Override
    public void runOnline(String id, TokenUser tokenUser) {
        EmpNoticeDO empNoticeDO = this.selectDOById(id, tokenUser.getSiteId());
        if (Objects.nonNull(empNoticeDO)) {
            empNoticeDO.setIsOnline(true);
            // 下线时间置为null
            empNoticeDO.setOfflineDate(null);
            // 根据发布时间更新下公告状态
            empNoticeDO.setStatus(CompanySysNoticeStatus.HAS.getValue());

            // 更新,公司公告,消息模块都更新
            updateById(empNoticeDO, tokenUser.getSiteId(), tokenUser.getUserId());

            List<String> noticeTypeList = Arrays.asList(empNoticeDO.getNoticeType().split(","));
            if (noticeTypeList.contains(HrConstants.NOTICE_TYPE_WECHAT)) {
                // 发送微信模板消息推送
                sendWeiXinTemp(empNoticeDO, tokenUser);
            } else if (noticeTypeList.contains(HrConstants.NOTICE_TYPE_TEXT)) {
                // 发短信
                sendTextTemp(empNoticeDO, tokenUser);
            } else if (noticeTypeList.contains(HrConstants.NOTICE_TYPE_EMAIL)) {
                // 发邮件
                sendEmailTemp(empNoticeDO, tokenUser);
            }
        }
    }

    @Override
    public void runOffline(String id, TokenUser tokenUser) {
        EmpNoticeDO empNoticeDO = this.selectDOById(id, tokenUser.getSiteId());
        if (Objects.nonNull(empNoticeDO)) {
            // 立即下线
            empNoticeDO.setOfflineDate(new Date());
            empNoticeDO.setIsOnline(false);
            empNoticeDO.setStatus(CompanySysNoticeStatus.OFFLINE.getValue());
            // 更新,公司公告,消息模块都更新
            updateById(empNoticeDO, tokenUser.getSiteId(), tokenUser.getUserId());
        }
    }

    @Override
    public EmpNoticeListVO findUserNotice(String userNoticeId, TokenUser tokenUser) {
        EmpNoticeDO empNoticeDO = selectDOById(userNoticeId, tokenUser.getSiteId());
        ParamException.notNull(empNoticeDO, "个人通知不存在或已删除");
        return empNoticeDO.to(EmpNoticeListVO.class);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void readUserNotice(TokenUser tokenUser, String userNoticeId, String... empIds) {
        if (empIds == null || empIds.length == 0) {
            throw new ParamException("请传递要修改的个人通知");
        }
        Example example = new Example(EmpNoticeDO.class);
        example.and()
                .andEqualTo("id", userNoticeId)
//                .andEqualTo("publishUserId", tokenUser.getUserId())
                .andEqualTo("valid", true)
                .andEqualTo("siteId", tokenUser.getSiteId());
        EmpNoticeDO empNoticeDO = empNoticeDAO.selectOneByExample(example);
        if (Objects.isNull(empNoticeDO)) {
            return;
        }
        // 未读员工
        String noReadEmpIdsStr = empNoticeDO.getNoReadEmpIds();
        if (StrKit.isEmpty(noReadEmpIdsStr)) {
            return;
        }
        String[] split = noReadEmpIdsStr.split(",");
        List<String> noReadList = Arrays.asList(split);
        if (CollectionUtils.isEmpty(noReadList)) {
            return;
        }
        // 本次要设为已读的员工id
        List<String> empIdArrayList = new ArrayList<>(Arrays.asList(empIds));

        if (StringUtils.isNotBlank(empNoticeDO.getNoReadEmpIds())) {
            String readEmpIds = empNoticeDO.getReadEmpIds();
            List<String> readEmpIdList = new ArrayList<>();
            if (StringUtils.isNotBlank(empNoticeDO.getReadEmpIds())) {
                readEmpIdList = Arrays.asList(readEmpIds.split(","));
            }
            // 已读员工id
            List<String> readEmpIdArrayList = new ArrayList<>(readEmpIdList);
            readEmpIdArrayList.addAll(empIdArrayList);

            List<String> allEmpIdList = Arrays.asList(empNoticeDO.getPublishEmpId().split(","));
            // 总员工id
            List<String> allEmpIdArrayList = new ArrayList<>(allEmpIdList);
            // 总员工 - 已读员工 = 未读员工
            allEmpIdArrayList.removeAll(readEmpIdArrayList);
            String noReadEmpIds = allEmpIdArrayList.parallelStream()
                    .distinct()
                    .collect(Collectors.joining(","));
            readEmpIds = readEmpIdArrayList.parallelStream()
                    .distinct()
                    .collect(Collectors.joining(","));
            empNoticeDO.setNoReadEmpIds(noReadEmpIds);
            empNoticeDO.setReadEmpIds(readEmpIds);
            empNoticeDO.setReadCount(readEmpIdArrayList.size());
            empNoticeDO.setNoReadCount(allEmpIdArrayList.size());

            // 更新个人通知阅读状态
            if (empNoticeDO.getReadCount() == 0) {
                empNoticeDO.setReadStatus(HrConstants.READ_STATUS_NO);
            } else if (empNoticeDO.getNoReadCount() == 0) {
                empNoticeDO.setReadStatus(HrConstants.READ_STATUS_READ);
            } else {
                empNoticeDO.setReadStatus(HrConstants.READ_STATUS_READ_SOME);
            }

            empNoticeDAO.updateByExampleSelective(empNoticeDO, example);
        }

    }


    /**
     * 根据查询参数，构建example
     *
     * @param empNoticeQuery 查询参数
     * @param siteId         所属站点id
     * @return example
     */
    private Example buildExample(EmpNoticeQuery empNoticeQuery, String siteId) {
        Example example = new Example(EmpNoticeDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        if (empNoticeQuery.getCompanyId() != null) {
            example.and().andEqualTo("companyId", empNoticeQuery.getCompanyId());
        }
        if (empNoticeQuery.getTitle() != null) {
            example.and().andLike("title", "%" + empNoticeQuery.getTitle() + "%");
        }
        if (empNoticeQuery.getContent() != null) {
            example.and().andEqualTo("content", empNoticeQuery.getContent());
        }
        if (empNoticeQuery.getContentHasStyle() != null) {
            example.and().andEqualTo("contentHasStyle", empNoticeQuery.getContentHasStyle());
        }
        if (empNoticeQuery.getPublishDateStart() != null &&
                empNoticeQuery.getPublishDateEnd() != null) {
            example.and().andBetween("publishDate", empNoticeQuery.getPublishDateStart(),
                    empNoticeQuery.getPublishDateEnd());
        }
        if (empNoticeQuery.getPublishEmpId() != null) {
            example.and().andEqualTo("publishEmpId", empNoticeQuery.getPublishEmpId());
        }
        if (empNoticeQuery.getPublishUserId() != null) {
            example.and().andEqualTo("publishUserId", empNoticeQuery.getPublishUserId());
        }
        if (empNoticeQuery.getProps() != null) {
            example.and().andEqualTo("props", empNoticeQuery.getProps());
        }
        if (empNoticeQuery.getNoticeIds() != null) {
            example.and().andEqualTo("noticeIds", empNoticeQuery.getNoticeIds());
        }
        if (empNoticeQuery.getCreateUserName() != null) {
            example.and().andEqualTo("createUserName", empNoticeQuery.getCreateUserName());
        }
        if (empNoticeQuery.getReadStatus() != null) {
            example.and().andEqualTo("readStatus", empNoticeQuery.getReadStatus());
        }
        example.orderBy("gmtCreate").desc();
        // 排序
//        ExampleKit.setExampleOrder(example,empNoticeQuery.getOrders());
        return example;
    }
}




